home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_069 / spool / spooler.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  429 lines

  1. /* SPOOLER.c - asynchronous file print program */
  2.  
  3. /*
  4. **    Date written: 04/23/86
  5. **    Author: Tim Holloway
  6. **        Compuserve: 73026,2026
  7. **        Bix: tholloway
  8. **        Fido node: 112/1 (Casa Mi Amiga).
  9. **
  10. **    As featured in Ami Project Magazine.
  11. **
  12. **    Version: 1.1
  13. **
  14. **    Copyright (C) 1986, by Tim Holloway.  This program may be
  15. **    freely distributed for non-commercial use only.  Use for commercial
  16. **    purposes without the express permission of the author is a violation
  17. **    of copyright law.
  18. **
  19. **    Description:
  20. **       This program is the intermediary between user requests submitted
  21. **    via the SPOOL program, and the printers driven by copies of the
  22. **    PRTSPOOL program.  Three queues are maintained: the logged-in user
  23. **    queue has an entry for each user (SPOOL or PRTSPOOL) logged into
  24. **    SPOOLER.  The filename queue is where filenames passed from SPOOL
  25. **    are stored until they can be passed on to PRTSPOOLs.  Finally, the
  26. **    waiting-printer queue is where requests for work from PRTSPOOL
  27. **    are held.
  28. **
  29. **    This program illustrates message passing and waiting for messages.
  30. **    Each message is the name of a file.  The named file will be printed,
  31. **    unless the name is SHUTDOWN, which causes SPOOLER to cease
  32. **    accepting login requests, and to respond to further messages with
  33. **    forced logouts.  SPOOL shuts down completely when the login queue
  34. **    has at last been emptied.
  35. **
  36. **    Change History:
  37. **
  38. **        11/19/86, TFH - added logic to FreeStruct SPOOL queue
  39. **    entries when they were removed from the SPOOL queue.  How
  40. **    embarassing!  Also, removed all printfs - does all talking via
  41. **    Intuition now.
  42. **
  43. **    Usage: RUN SPOOLER
  44. */
  45.  
  46. #include <exec/types.h>
  47. #include <exec/exec.h>
  48. #include <exec/alerts.h>
  49. #include <libraries/dosextens.h>
  50.  
  51. #include "stdio.h"
  52. #include "spool.h"
  53.  
  54. #define NOT !            /* A la RJ Mical */
  55. #define USER_NAME_LENGTH 33    /* maximum length of a logged user name */
  56.  
  57. /*
  58. **    The following is an information hider - it insulates the workings
  59. **    of this program against changes in the DOS and from compiler
  60. **    dependencies.  Also makes program more readable.
  61. */
  62.  
  63. #define on_port(mport) (1L << mport->mp_SigBit)
  64.  
  65. /*    A convenient allocator for structures: */
  66.  
  67. #define AllocStruct(structype, pool) (structype *) \
  68.     AllocMem (sizeof(structype), pool)
  69.  
  70. /* And its converse... */
  71.  
  72. #define FreeStruct(area, structype) FreeMem(area, sizeof(structype))
  73.  
  74. /* Hide the details of test for an empty list */
  75.  
  76. #define EmptyList(list) (list.lh_Head->ln_Succ == NULL)
  77.  
  78. #define streq(a,b) (strcmp(a,b) == 0)    /* an old favorite */
  79.  
  80. /*
  81. **    Logged-in user queue element definition:
  82. */
  83.  
  84. typedef struct {
  85.     struct Node lu_node;
  86.     char lu_name[USER_NAME_LENGTH];
  87. } logged_user;
  88.  
  89. /* Prototypes. Lie slightly about function return types. */
  90.  
  91. extern logged_user *Find_Name(struct List *, TEXT *);
  92.  
  93. extern SPOOLmsg *RemHead (struct List *),
  94.         *GetMsg (struct MsgPort *);
  95.  
  96.  
  97.  
  98. /* Global variables. */
  99.  
  100. BOOL
  101.     spooler_running;
  102.     spooler_closing_down;
  103.  
  104.  
  105. static void
  106. make_id (packet, str)    /* create a unique login ID */
  107. SPOOLmsg *packet;    /* based on the sender's reply port address */
  108. TEXT *str;
  109. {
  110.     sprintf (str, "SPOOL User %lx", &packet->minfo.mn_ReplyPort);
  111. }
  112.  
  113. static void
  114. error (msg)        /* report error */
  115. TEXT *msg;
  116. {
  117.     Gripe ("SPOOLER:", msg, "");
  118. }
  119.  
  120. /*************************************************************************
  121. **                                    **
  122. **    Log users in and out.  Users are logged to ensure that nobody    **
  123. **    tries to send spool requests once the spooler starts closing    **
  124. **    down.                                **
  125. **                                    **
  126. *************************************************************************/
  127.  
  128. struct List login_list;    /* anchor the list of logged-in users */
  129.  
  130. struct List file_queue;    /* ditto the list of filenames to spool */
  131.  
  132. struct List waiting_printers;    /* unemployed printer list */
  133.  
  134. static void
  135. login(packet)
  136. register SPOOLmsg *packet;
  137. {
  138.     register logged_user *user;
  139.  
  140.     packet->log_status = LOG_OUT;    /* assume the worst */
  141.     if (NOT spooler_closing_down)
  142.     {
  143. /*        printf ("Log in: "); */
  144.         user = AllocStruct (logged_user, MEMF_PUBLIC | MEMF_CLEAR);
  145.         if (user == NULL)
  146.             error ("Couldn't get memory to log in user");
  147.         else
  148.         {
  149.             user->lu_node.ln_Name = user->lu_name;
  150.             user->lu_node.ln_Type = NT_UNKNOWN;
  151.             user->lu_node.ln_Pri = 0;
  152.             make_id (packet, user->lu_name);
  153.             AddTail (&login_list, user);
  154. /*    printf ("%s completed\n", user->lu_name); */
  155.             packet->log_status = LOGGED;
  156.         }
  157.     }
  158. }
  159.  
  160. static void
  161. logout(packet)
  162. register SPOOLmsg *packet;
  163. {
  164.     char user_id[USER_NAME_LENGTH];
  165.     register logged_user *user;
  166.  
  167.     make_id (packet, user_id);
  168.     user = (logged_user *) FindName (&login_list, user_id);
  169.     if (user == NULL)
  170.     {
  171.         error ("Logout failed - could not find user ID:");
  172.         error (user_id);
  173.     }
  174.     else
  175.     {
  176. /*    printf ("%s logged out.\n", user_id); */
  177.         Remove(user);    /* ... from the logged-user list */
  178.         FreeStruct(user, logged_user);
  179.         packet->log_status = LOG_OUT;
  180.         if (EmptyList(login_list) && spooler_closing_down)
  181.             spooler_running = FALSE;
  182.     }
  183. }
  184.  
  185.  
  186. /*************************************************************************
  187. **                                    **
  188. **    Spooler shutdown routines.                    ** 
  189. **                                    **
  190. *************************************************************************/
  191.  
  192. static void
  193. purge_queues()        /* throw away any outstanding SPOOL requests */
  194. {            /* modified v1.1 */
  195.     SPOOLmsg *qp;
  196.  
  197.     while ( (qp = (SPOOLmsg *) RemHead(&file_queue)) != NULL)
  198.         FreeStruct(qp, SPOOLmsg);
  199. }
  200.  
  201. static void
  202. terminate_printers()        /* tell the printers to get lost! */
  203. {
  204.     register SPOOLmsg *bail_out;
  205.  
  206.     while (
  207.          (bail_out = (SPOOLmsg *)RemHead(&waiting_printers))
  208.               !=
  209.          NULL
  210.           )
  211.     {
  212.  
  213. /* printf ("Force off PRT %lx\n", bail_out); */
  214.  
  215.         logout(bail_out);    /* remove from log */
  216.         bail_out->log_status = LOG_OUT;
  217.         ReplyMsg(bail_out);
  218.     }
  219. }
  220.  
  221. /*************************************************************************
  222. **                                    **
  223. **    Process inbound SPOOL requests.                    **
  224. **    If somebody wants the request, pass it on, else make a copy    **
  225. **    of it, and queue the copy.                    **
  226. **                                    **
  227. *************************************************************************/
  228.  
  229. static void
  230. pass_request(packet)
  231. register SPOOLmsg *packet;
  232. {
  233.     register SPOOLmsg *msg_requested;
  234.  
  235.     if ( (msg_requested= RemHead(&waiting_printers)) == NULL)
  236.     {
  237.         msg_requested =
  238.             AllocStruct (SPOOLmsg, MEMF_PUBLIC);
  239.         movmem (packet, msg_requested, sizeof(SPOOLmsg));
  240.  
  241. /* printf ("Queuing request for %s\n", packet->filename); */
  242.  
  243.         AddTail (&file_queue, msg_requested);
  244.     }
  245.     else    /* send the name to the PRTSPOOL's query */
  246.     {
  247.         strcpy (msg_requested->filename, packet->filename);
  248.         ReplyMsg (msg_requested);
  249.     }
  250. }
  251.  
  252. /*************************************************************************
  253. **                                    **
  254. **    Process inbound SPOOL requests.                    **
  255. **                                    **
  256. *************************************************************************/
  257.  
  258. static void
  259. handle_input(packet)
  260. register SPOOLmsg *packet;
  261. {
  262. /* printf ("Inbound message from %lx\n", packet); */
  263.  
  264.     switch (packet->log_status)
  265.     {
  266.     case LOG_IN:
  267.         login (packet);
  268.         break;
  269.     case LOG_OUT:
  270.         logout (packet);
  271.         break;
  272.     case LOGGED:
  273.         if (spooler_closing_down)
  274.             logout(packet);        /* sorry! */
  275.         else
  276.         if (streq(packet->filename, SHUTDOWN))
  277.         {
  278.             spooler_closing_down = TRUE;
  279.             purge_queues();
  280.             terminate_printers();
  281.         }
  282.         else
  283.             pass_request (packet);
  284.         break;
  285.     default: error ("SPL: Invalid log request");
  286.     }
  287.     ReplyMsg (packet);    /* return to owner! */
  288. }
  289.  
  290. /*************************************************************************
  291. **                                    **
  292. **    Process outbound SPOOL requests.                **
  293. **                                    **
  294. **    Notice that since the PRTSPOOL messages contain List nodes,    **
  295. **    they can be queued directly!                    **
  296. **                                    **
  297. *************************************************************************/
  298.  
  299. static void
  300. prt_request(packet)
  301. register SPOOLmsg *packet;
  302. {
  303.     register SPOOLmsg *msg_requested;
  304.  
  305.     if ( (msg_requested= RemHead(&file_queue)) == NULL)
  306.     {
  307. /* printf ("Queuing PRT request from %lx.\n", packet); */
  308.  
  309.         AddTail (&waiting_printers, packet);
  310.     }
  311.     else
  312.     {
  313.  
  314. /* printf ("dequeueing and outputting %s\n", msg_requested->filename); */
  315.  
  316.         strcpy (packet->filename, msg_requested->filename);
  317.         FreeStruct (msg_requested, SPOOLmsg);    /* V1.1 */
  318.         ReplyMsg (packet);
  319.     }
  320. }
  321.  
  322. /*************************************************************************
  323. **                                    **
  324. **    Process PRTSPOOL requests.                    **
  325. **                                    **
  326. *************************************************************************/
  327.  
  328. static void
  329. handle_output(packet)
  330. register SPOOLmsg *packet;
  331. {
  332. /* printf ("PRTSPOOL message from %lx\n", packet); */
  333.  
  334.     switch (packet->log_status)
  335.     {
  336.     case LOG_IN:
  337.         login (packet);
  338.         break;
  339.     case LOG_OUT:
  340.         logout (packet);
  341.         break;
  342.     case LOGGED:
  343.         if (spooler_closing_down)
  344.             logout(packet);        /* sorry! */
  345.         else
  346.         {
  347.             prt_request (packet);
  348.             return;    /* reply done in prt_request */
  349.         }
  350.         break;
  351.     default: error ("PRT: Invalid log request");
  352.     }
  353.     ReplyMsg (packet);    /* return to owner! */
  354. }
  355.  
  356. /*************************************************************************
  357. **                                    **
  358. **    Gentlemen, start your SPOOLers.                    **
  359. **                                    **
  360. *************************************************************************/
  361.  
  362. struct Library *IntuitionBase, *OpenLibrary();
  363.  
  364. void
  365. main (argc, argv)
  366. int argc;
  367. char *argv[];
  368. {
  369.    struct MsgPort *FindPort(), *CreatePort(), *inport, *outport;
  370.    SPOOLmsg *packet;
  371.    struct Process *myprocess, *FindTask();
  372.  
  373.    if ( (IntuitionBase = OpenLibrary("intuition.library", 0)) == NULL)
  374.    {
  375.     Alert (AT_Recovery + AG_OpenLib + AO_Intuition, NULL);
  376.     exit(20);
  377.    }
  378.  
  379.     /* it doesn't hurt to run multiple SPOOLERS at once -
  380.        but why bother?  Only one will get the messages! */
  381.  
  382.    if(FindPort(SPOOL_ME) != NULL)
  383.    {
  384.     error ("SPOOLER is already active!");
  385.     goto abort;
  386.    }
  387.  
  388.    if ((inport = CreatePort(SPOOL_ME,0)) == NULL)
  389.    {
  390.       error ("Unable to create spool message port\n");
  391.       goto abort;
  392.    }
  393.  
  394.    if ((outport = CreatePort(GIMME_A_FILE,0)) == NULL)
  395.    {
  396.       error ("Unable to create spool message port\n");
  397.       DeletePort (inport);
  398.       goto abort;
  399.    }
  400.  
  401.    NewList (&file_queue);
  402.    NewList (&login_list);
  403.    NewList (&waiting_printers);
  404.  
  405.  
  406.      /* raise priority - this program is low-overhead (mostly Waiting) */
  407.  
  408.     myprocess = FindTask(NULL);
  409.     (void) SetTaskPri (myprocess, SPOOLER_PRIORITY);
  410.  
  411. /* printf ("input message port for %s is at %lx\n", SPOOL_ME, inport); */
  412.  
  413.    for (spooler_running = TRUE; spooler_running ; )
  414.    {
  415.  
  416. /* printf ("Wait for port...\n"); */
  417.       Wait (on_port(inport) | on_port(outport)); /* '|', NOT '||' ! */
  418.       while ( (packet = GetMsg (inport)) != NULL) handle_input(packet);
  419.  
  420.       while ( (packet = GetMsg (outport)) != NULL) handle_output(packet);
  421.    }
  422. /*   printf ("Spooling has been terminated\n"); */
  423.    DeletePort (inport);
  424.    DeletePort (outport);
  425.  
  426. abort:
  427.    CloseLibrary(IntuitionBase);
  428. }
  429.